﻿using System;
using System.Collections.Specialized;
/// <summary>Behaviors for TabControl.
/// </summary>
using System.Windows;
using System.Windows.Controls;


namespace Simhopp.Client
{
    public class TabControlBehavior
    {
        /// <summary>Whether to focus the first visible tab.

        /// </summary>
        /// <remarks>Setting the FocusFirstVisibleTab
        /// attached property to true will focus the next visible tab when
        /// the current selected tab's Visibility property is set to Collapsed or Hidden.</remarks>

        public static DependencyProperty FocusFirstVisibleTabProperty =
            DependencyProperty.RegisterAttached("FocusFirstVisibleTab", 
                typeof(bool),
                typeof(TabControlBehavior),
                new FrameworkPropertyMetadata(OnFocusFirstVisibleTabPropertyChanged));

        /// <summary>Gets the focus first visible tab value of the given element.

        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>

        public static bool GetFocusFirstVisibleTab(TabControl element)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            return (bool)element.GetValue(FocusFirstVisibleTabProperty);
        }

        /// <summary>Sets the focus first visible tab value of the given element.

        /// </summary>
        /// <param name="element">The element.</param>
        /// <param name="value">if set to <c>true</c> [value].</param>

        public static void SetFocusFirstVisibleTab(TabControl element, bool value)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }
            element.SetValue(FocusFirstVisibleTabProperty, value);
        }

        /// <summary>Determines whether the value of the dependency property <c>IsFocused</c> has change.

        /// </summary>
        /// <param name="d">The dependency object.</param>
        /// <param name="e">The <see

        ///   cref="System.Windows.DependencyPropertyChangedEventArgs"/>
        ///   instance containing the event data.</param>
        private static void OnFocusFirstVisibleTabPropertyChanged(
                DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var tabControl = d as TabControl;
            if (tabControl != null)
            {
                // Attach or detach the event handlers.

                if ((bool)e.NewValue)
                {
                    // Enable the attached behavior.
                    tabControl.Items.CurrentChanged += new EventHandler(TabControl_Items_CurrentChanged);
                    var collection = tabControl.Items as INotifyCollectionChanged;
                    if (collection != null)
                    {
                        collection.CollectionChanged +=
                          new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
                    }
                }
                else
                {
                    // Disable the attached behavior.
                    tabControl.Items.CurrentChanged -= new EventHandler(TabControl_Items_CurrentChanged);
                    var collection = tabControl.Items as INotifyCollectionChanged;
                    if (collection != null)
                    {
                        collection.CollectionChanged -=
                          new NotifyCollectionChangedEventHandler(TabControl_Items_CollectionChanged);
                    }
                    // Detach handlers from the tab items.

                    foreach (var item in tabControl.Items)
                    {
                        TabItem tab = item as TabItem;
                        if (tab != null)
                        {
                            tab.IsVisibleChanged -=
                              new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                        }
                    }
                }
            }
        }


        /// <summary>Handles the CollectionChanged event of the TabControl.Items collection.
        /// </summary>
        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see
        ///    cref="System.Collections.Specialized.NotifyCollectionChangedEventArgs"/>
        ///    instance containing the event data.</param>

        static void TabControl_Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            // Attach event handlers to each tab so that when the Visibility property changes of the selected tab,
            // the focus can be shifted to the next (or previous, if not next tab available) tab.
            var collection = sender as ItemCollection;
            if (collection != null)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                    case NotifyCollectionChangedAction.Remove:
                    case NotifyCollectionChangedAction.Replace:
                        // Attach event handlers to the Visibility and IsEnabled properties.

                        if (e.NewItems != null)
                        {
                            foreach (var item in e.NewItems)
                            {
                                TabItem tab = item as TabItem;
                                if (tab != null)
                                {
                                    tab.IsVisibleChanged +=
                                      new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                                }
                            }
                        }
                        // Detach event handlers from old items.

                        if (e.OldItems != null)
                        {
                            foreach (var item in e.OldItems)
                            {
                                TabItem tab = item as TabItem;
                                if (tab != null)
                                {
                                    tab.IsVisibleChanged -=
                                      new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                                }
                            }
                        }
                        break;
                    case NotifyCollectionChangedAction.Reset:
                        // Attach event handlers to the Visibility and IsEnabled properties.

                        foreach (var item in collection)
                        {
                            TabItem tab = item as TabItem;
                            if (tab != null)
                            {
                                tab.IsVisibleChanged +=
                                  new DependencyPropertyChangedEventHandler(TabItem_IsVisibleChanged);
                            }
                        }
                        break;
                    case NotifyCollectionChangedAction.Move:
                    default:
                        break;
                }

                // Select the first element if necessary.

                if (collection.Count > 0 && collection.CurrentItem == null)
                {
                    collection.MoveCurrentToFirst();
                }
            }
        }


        /// <summary>Handles the CurrentChanged event of the TabControl.Items collection.
        /// </summary>
        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see cref="System.EventArgs"/>
        /// instance containing the event data.</param>

        static void TabControl_Items_CurrentChanged(object sender, EventArgs e)
        {
            var collection = sender as ItemCollection;
            if (collection != null)
            {
                UIElement element = collection.CurrentItem as UIElement;
                if (element != null && element.Visibility != Visibility.Visible)
                {
                    element.Dispatcher.BeginInvoke(new Action(() => collection.MoveCurrentToNext()),
                       System.Windows.Threading.DispatcherPriority.Input);
                }
            }
        }


        /// <summary>Handles the IsVisibleChanged event of the tab item.
        /// </summary>
        /// <param name="sender">The source of the event.</param>

        /// <param name="e">The <see
        ///   cref="System.Windows.DependencyPropertyChangedEventArgs"/>
        ///   instance containing the event data.</param>

        static void TabItem_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            TabItem tab = sender as TabItem;
            if (tab != null && tab.IsSelected && tab.Visibility != Visibility.Visible)
            {
                // Move to the next tab item.

                TabControl tabControl = tab.Parent as TabControl;
                if (tabControl != null)
                {
                    tabControl.Items.MoveCurrentToFirst();
                }
            }
        }
    }
}